/*
 * Copyright (C) 2008-2011 CBDP Consortium
 * 
 * All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.
 * 
 * This software consists of contributions made by many individuals, 
 * listed below:
 *
 * Author: 	Xabier Laiseca <xabier.laiseca@deusto.es>
 * 			David Ausín <david.ausin@deusto.es>
 */
package cbdp.server.contextreasoner.impl.contextmanager.online.model;

import static cbdp.server.contextreasoner.impl.contextmanager.online.model.Checker.*;
import cbdp.server.contextreasoner.model.PrimitiveDatatypeProperty;
import cbdp.server.contextreasoner.model.exceptions.InvalidDatatypeException;

import com.hp.hpl.jena.ontology.DatatypeProperty;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.shared.Lock;

public class EagerSavingPrimitiveDatatypeProperty extends EagerSavingGenericProperty implements PrimitiveDatatypeProperty
{
	private final static String INCORRECT_DATATYPE_MESSAGE = "The type of the property is not correct";
	
	
	private Literal literal;
	
	@Override
	public void setStatement(final Statement statement)
	{
		super.setStatement(statement);
		
		this.literal = statement.getLiteral();
	}

	@Override
	public boolean getBooleanValue() throws InvalidDatatypeException
	{
		return getGenericValue(Boolean.class);
	}

	@Override
	public char getCharValue() throws InvalidDatatypeException
	{
		return getGenericValue(Character.class);
	}

	@Override
	public double getDoubleValue() throws InvalidDatatypeException
	{
		return getGenericValue(Double.class);
	}

	@Override
	public float getFloatValue() throws InvalidDatatypeException
	{
		return getGenericValue(Float.class);
	}

	@Override
	public int getIntValue() throws InvalidDatatypeException
	{
		return getGenericValue(Integer.class);
	}

	@Override
	public long getLongValue() throws InvalidDatatypeException
	{
		return getGenericValue(Long.class);
	}

	@Override
	public String getStringValue() throws InvalidDatatypeException
	{
		return getGenericValue(String.class);
	}
	
	@Override
	public void notifyDeleted()
	{
		literal = null;
	}

	private <T> T getGenericValue(final Class<T> clazz) throws InvalidDatatypeException
	{
		try
		{
			ontModel.enterCriticalSection(Lock.READ);
			
			return clazz.cast(literal.getValue());
		}
		catch (ClassCastException e)
		{
			throw new InvalidDatatypeException(INCORRECT_DATATYPE_MESSAGE, e);
		}
		finally
		{
			ontModel.leaveCriticalSection();
		}
	}

	@Override
	public void setValue(final boolean value) throws InvalidDatatypeException
	{
		checkNullParameter(value, "value");

		ontModel.enterCriticalSection(Lock.WRITE);
		
		try
		{
			final Literal literal = ontModel.createTypedLiteral(value);
			
			checkValidValue(literal, statement.getPredicate().as(DatatypeProperty.class));
			statement.changeLiteralObject(value);
		}
		finally
		{
			ontModel.leaveCriticalSection();
		}
	}
	
	@Override
	public void setValue(final char value) throws InvalidDatatypeException
	{
		checkNullParameter(value, "value");
		
		ontModel.enterCriticalSection(Lock.WRITE);
		
		try
		{
			final Literal literal = ontModel.createTypedLiteral(value);
			
			checkValidValue(literal, statement.getPredicate().as(DatatypeProperty.class));
			statement.changeLiteralObject(value);
		}
		finally
		{
			ontModel.leaveCriticalSection();
		}
	}
	
	@Override
	public void setValue(final double value) throws InvalidDatatypeException
	{
		checkNullParameter(value, "value");
		
		ontModel.enterCriticalSection(Lock.WRITE);
		
		try
		{
			final Literal literal = ontModel.createTypedLiteral(value);
			
			checkValidValue(literal, statement.getPredicate().as(DatatypeProperty.class));
			statement.changeLiteralObject(value);
		}
		finally
		{
			ontModel.leaveCriticalSection();
		}
	}
	
	@Override
	public void setValue(final float value) throws InvalidDatatypeException
	{
		checkNullParameter(value, "value");
		
		ontModel.enterCriticalSection(Lock.WRITE);
		
		try
		{
			final Literal literal = ontModel.createTypedLiteral(value);
			
			checkValidValue(literal, statement.getPredicate().as(DatatypeProperty.class));
			statement.changeLiteralObject(value);
		}
		finally
		{
			ontModel.leaveCriticalSection();
		}
	}
	
	@Override
	public void setValue(final int value) throws InvalidDatatypeException
	{
		checkNullParameter(value, "value");
		
		ontModel.enterCriticalSection(Lock.WRITE);
		
		try
		{
			final Literal literal = ontModel.createTypedLiteral(value);
			
			checkValidValue(literal, statement.getPredicate().as(DatatypeProperty.class));
			statement.changeLiteralObject(value);
		}
		finally
		{
			ontModel.leaveCriticalSection();
		}
	}
	
	@Override
	public void setValue(final long value) throws InvalidDatatypeException
	{
		checkNullParameter(value, "value");
		
		ontModel.enterCriticalSection(Lock.WRITE);
		
		try
		{
			final Literal literal = ontModel.createTypedLiteral(value);
			
			checkValidValue(literal, statement.getPredicate().as(DatatypeProperty.class));
			statement.changeLiteralObject(value);
		}
		finally
		{
			ontModel.leaveCriticalSection();
		}
	}

	@Override
	public void setValue(final String value) throws InvalidDatatypeException
	{
		checkNullParameter(value, "value");
		
		ontModel.enterCriticalSection(Lock.WRITE);
		
		try
		{
			final Literal literal = ontModel.createTypedLiteral(value);
			
			checkValidValue(literal, statement.getPredicate().as(DatatypeProperty.class));
			statement.changeObject(value);
		}
		finally
		{
			ontModel.leaveCriticalSection();
		}
	}
}
